
class FartMonkeyScene extends BaseScene {
    private _world: Box2D.Dynamics.b2World = null
    private _debug: Box2D.Dynamics.b2DebugDraw = null
    private _barrier: Array<Box2D.Dynamics.b2Body> = null
    private _ball: Box2D.Dynamics.b2Body = null
    private _step: number = 30
    private _p2m: number = 10
    private _lookAtX: number = 0
    private _lookAtY: number = 0
    private bHeight: number = 0
    private bWidth: number = 0
    private _bg: TitleMap
    constructor() {
        super()
    }

    public init(): void {
        this._bg = new TitleMap()
        this._bg.initMap()
        LayerManager.Game_Bg.addChild(this._bg)

        var gravity: Box2D.Common.Math.b2Vec2 = new Box2D.Common.Math.b2Vec2(0, 8 * this._step / this._p2m);
        this._world = new Box2D.Dynamics.b2World(gravity, true)

        {
            let bodyDef = new Box2D.Dynamics.b2BodyDef()
            bodyDef.type = Box2D.Dynamics.b2Body.b2_staticBody
            bodyDef.bullet = true
            bodyDef.linearDamping = 0
            bodyDef.angularDamping = 0
            bodyDef.fixedRotation = true
            bodyDef.allowSleep = true

            console.log(App.StageUtils.getWidth())
            console.log(App.StageUtils.getHeight())

            this.bHeight = App.StageUtils.getHeight() * 2 / 3
            this.bWidth = App.StageUtils.getWidth()
            let shape = new Box2D.Collision.Shapes.b2PolygonShape()
            let w = 10
            let h = this.bHeight
            w = w / this._p2m / 2
            h = h / this._p2m / 2
            //shape.SetAsOrientedBox(w, h, new Box2D.Common.Math.b2Vec2(0, h))
            shape.SetAsBox(w, h)

            let fixtureDef = new Box2D.Dynamics.b2FixtureDef()
            fixtureDef.shape = shape
            fixtureDef.friction = 1
            fixtureDef.restitution = 0
            if (false) {
                let posX = 10
                let posY = App.StageUtils.getHeight()

                shape.SetAsBox(100, 10)
                bodyDef.position.x = posX / this._p2m
                bodyDef.position.y = posY / this._p2m
                let body = this._world.CreateBody(bodyDef)
                body.CreateFixture(fixtureDef)
            }
            else {
                this._barrier = new Array<Box2D.Dynamics.b2Body>(6)
                for (let i = 0; i < this._barrier.length; i += 2) {
                    let posX = 10
                    let posY = (i / 2 - 1) * this.bHeight

                    bodyDef.position.x = posX / this._p2m
                    bodyDef.position.y = posY / this._p2m
                    let body = this._world.CreateBody(bodyDef)
                    body.CreateFixture(fixtureDef)
                    this._barrier[i] = body
                }
                for (let i = 0; i < this._barrier.length; i += 2) {
                    let posX = this.bWidth - 10
                    let posY = (i / 2 - 1) * this.bHeight

                    bodyDef.position.x = posX / this._p2m
                    bodyDef.position.y = posY / this._p2m
                    shape.SetAsBox(w, h)
                    let body = this._world.CreateBody(bodyDef)
                    body.CreateFixture(fixtureDef)
                    this._barrier[i + 1] = body
                }
            }
        }
        {
            let bodyDef = new Box2D.Dynamics.b2BodyDef()
            bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody
            bodyDef.bullet = true
            bodyDef.linearDamping = 1
            bodyDef.angularDamping = 0.2
            bodyDef.fixedRotation = false
            bodyDef.allowSleep = true
            bodyDef.position.x = App.StageUtils.getWidth() / 2 / this._p2m
            bodyDef.position.y = 0 //App.StageUtils.getHeight() / 2 / this._p2m
            bodyDef.angle = Math.PI / 2

            let fixtureDef = new Box2D.Dynamics.b2FixtureDef()
            fixtureDef.density = 1
            fixtureDef.friction = 0
            fixtureDef.restitution = 0.8

            this._ball = this._world.CreateBody(bodyDef)
            {
                let shape = new Box2D.Collision.Shapes.b2PolygonShape()
                shape.SetAsBox(10 / this._p2m, 20 / this._p2m)
                fixtureDef.shape = shape
                this._ball.CreateFixture(fixtureDef)
            }
            if (true) {
                let shape = new Box2D.Collision.Shapes.b2PolygonShape()
                shape.SetAsBox(40 / this._p2m, 10 / this._p2m)
                shape.SetAsOrientedBox(40 / this._p2m, 10 / this._p2m, new Box2D.Common.Math.b2Vec2(10 / this._p2m, -10 / this._p2m))
                fixtureDef.shape = shape
                this._ball.CreateFixture(fixtureDef)
            }
            if (true) {
                let shape = new Box2D.Collision.Shapes.b2PolygonShape()
                shape.SetAsOrientedBox(5 / this._p2m, 5 / this._p2m, new Box2D.Common.Math.b2Vec2(50 / this._p2m, -10 / this._p2m))
                fixtureDef.shape = shape
                this._ball.CreateFixture(fixtureDef)
            }
        }

        //App.StageUtils.getStage().addEventListener(egret.Event.ENTER_FRAME, this.loop, this);

        this._debug = new Box2D.Dynamics.b2DebugDraw();
        var s: egret.Sprite = new egret.Sprite();
        this._debug.SetSprite(s);
        this._bg.addChild(s)
        this._debug.SetDrawScale(this._p2m);
        this._debug.SetLineThickness(1);
        this._debug.SetAlpha(0.8);
        this._debug.SetFillAlpha(0.5);
        this._debug.SetFlags(Box2D.Dynamics.b2DebugDraw.e_shapeBit);
        this._world.SetDebugDraw(this._debug);
    }

    public onEnter(): void {
        super.onEnter()

        this.init()

        this.addLayer(LayerManager.Game_Bg)
        this.addLayer(LayerManager.UI_Game)

        LayerManager.UI_Game.addEventListener(egret.TouchEvent.TOUCH_TAP, this.onTap, this)
        LayerManager.UI_Game.touchEnabled = true
    }

    public onExit(): void {
        super.onExit()
    }

    public enterFrame(time: number) {
        this.phyLoop()
        if (this._ball != null) {
            let pos = this._ball.GetPosition()
            this.lookAt(pos.x * this._p2m, pos.y * this._p2m)
        }
    }

    public lookAt(x, y: number) {
        this._bg.LookAt(App.StageUtils.getWidth() / 2, y)
        //this._bg.x = 0
        //this._bg.y = -y + App.StageUtils.getHeight() / 2
        let index = -Math.floor(this._bg.y / this.bHeight)
        let _SetPos = function (scene: FartMonkeyScene, i: number) {
            let pos = scene._barrier[i].GetPosition()
            pos.y = ((index + Math.floor(i / 2) - 1) * scene.bHeight) / scene._p2m
            scene._barrier[i].SetPosition(pos)
        }

        if (this._barrier != null) {
            for (let i = 0; i < this._barrier.length; i += 2) {
                _SetPos(this, i)
                _SetPos(this, i + 1)
            }
        }
        this._lookAtX = x
        this._lookAtY = y
        //console.debug("LootAt (%d,\t%d)", this._lookAtX, this._lookAtY)
    }

    public phyLoop() {
        this._world.Step(1 / this._step, 3, 6);
        if (this._debug != null) {
            this._world.DrawDebugData();
        }
        let velocity = this._ball.GetLinearVelocity()
        let maxVY = 15
        if (velocity.y > maxVY) {
            velocity.y -= 1
            if (velocity.y < maxVY) {
                velocity.y = maxVY
            }
        }
        this._ball.SetLinearVelocity(velocity)

        let maxAV = 3
        if (this._ball.GetAngularVelocity() > maxAV) {
            this._ball.SetAngularVelocity(maxAV)
        } else if (this._ball.GetAngularVelocity() < -maxAV) {
            this._ball.SetAngularVelocity(-maxAV)
        }
        
        
        console.debug("GetLinearVelocity:(%f)", this._ball.GetAngularVelocity())
    }

    private onTap(e: egret.Event) {
        console.debug("onTap")
        let absForce = 2000
        let angle = this._ball.GetAngle() + Math.PI
        let force = new Box2D.Common.Math.b2Vec2(absForce * Math.cos(angle), absForce * Math.sin(angle))
        let point = new Box2D.Common.Math.b2Vec2(50 / this._p2m, -10 / this._p2m)
        this._ball.ApplyImpulse(force, this._ball.GetWorldPoint(point))
        console.debug("angle:%f force:(%f,%f)", angle, force.x, force.y)
    }
}